package com.assistant.core;

import ai.picovoice.porcupine.Porcupine;
import com.assistant.ai.NLUModule;
import com.assistant.ai.STTModule;
import com.assistant.ai.TTSModule;
import com.assistant.audio.MicrophoneModule;
import com.assistant.audio.VADModule;
import com.assistant.command.CommandDispatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Anyang
 * @version 1.0.0
 * @date 2025/10/25 05:10:04
 * @description 助手应用的核心引擎：语音识别、语音合成、指令处理、状态管理
 */
public class AssistantEngine {
    private static final Logger logger = LoggerFactory.getLogger(AssistantEngine.class);

    // --- 状态机 ---
    public enum State {
        SLEEPING,    // 状态1：休眠，仅监听唤醒词
        LISTENING,   // 状态2：已唤醒，正在监听指令 (VAD开启)
        PROCESSING   // 状态3：正在处理 (NLU/STT)，暂停监听
    }
    private volatile State currentState = State.SLEEPING;

    // --- 核心模块 ---
    private final TTSModule ttsModule;
    private final STTModule sttModule;
    private final NLUModule nluModule;
    private final CommandDispatcher dispatcher;
    private final MicrophoneModule micModule;
    private final Porcupine porcupine;
    private final VADModule vadModule;

    /**
     * 构造函数：初始化所有模块
     */
    public AssistantEngine() {
        logger.info("【引擎】开始初始化核心模块...");
        // 1. 初始化 AI 模块
        this.ttsModule = new TTSModule();
        this.nluModule = new NLUModule(this);
        this.sttModule = new STTModule(ttsModule);
        this.dispatcher = new CommandDispatcher(nluModule, ttsModule);

        // 2. 初始化 Porcupine (唤醒词)
        try {
            this.porcupine = new Porcupine.Builder()
                    .setAccessKey(Config.PICOVOICE_ACCESS_KEY)
                    .setKeywordPaths(new String[]{Config.KEYWORD_PATH})
                    .setModelPath(Config.PORCUPINE_MODEL_PATH)
                    .build();
            logger.info("【引擎】Porcupine (唤醒词) 初始化成功，帧长度: {}", porcupine.getFrameLength());
        } catch (Exception e) {
            logger.error("【引擎】Porcupine 初始化失败!", e);
            throw new RuntimeException("Porcupine failed to initialize", e);
        }
        
        // 3. 初始化 VAD 模块
        this.vadModule = new VADModule(
                Config.VAD_ENERGY_THRESHOLD,
                Config.VAD_SILENCE_FRAMES_REQUIRED
        );

        // 4. 初始化麦克风 (回调 this::processAudioFrame)
        this.micModule = new MicrophoneModule(porcupine, this::processAudioFrame);
        logger.info("【引擎】所有模块初始化完毕。");
    }

    /**
     * 启动助手引擎：
     * 1. 启动麦克风流
     * 2. 播放欢迎语
     * 3. 进入休眠
     */
    public void start() {
        logger.info("【引擎】启动中...");
        micModule.startStreaming();

        // 播放欢迎语（修复自唤醒）
        setAssistantState(State.PROCESSING);
        ttsModule.speak("你好，我是小牛哥");
        logger.info("【引擎】启动完毕，进入 SLEEPING 状态。");
        setAssistantState(State.SLEEPING);
    }

    /**
     * 停止助手引擎（用于关闭钩子）
     */
    public void stop() {
        logger.info("--- 正在关闭 AI 助手 ---");
        if (micModule != null && micModule.isCapturing()) {
            micModule.stopStreaming();
        }
        if (porcupine != null) {
            porcupine.delete();
        }
        logger.info("--- 资源已释放，助手已退出 ---");
    }

    /**
     * 核心：处理音频帧的回调 (在 MicrophoneModule 线程中被调用)
     * @param frame 512 个 short (来自麦克风)
     */
    private void processAudioFrame(short[] frame) {
        try {
            switch (currentState) {
                case SLEEPING:
                    int keywordIndex = porcupine.process(frame);
                    if (keywordIndex == 0) { // 0 对应 "小牛哥"
                        logger.info("【唤醒】检测到 '小牛哥'!");
                        vadModule.reset();
                        setAssistantState(State.LISTENING);
                        ttsModule.speak("我在");
                    }
                    break;

                case LISTENING:
                    boolean speechEnded = vadModule.processFrame(frame);
                    if (speechEnded) {
                        setAssistantState(State.PROCESSING);
                        final byte[] commandAudio = vadModule.getAndClearAudioBuffer();
                        // 异步处理指令，避免阻塞音频线程
                        new Thread(() -> handleCommand(commandAudio), "Command-Processor-Thread").start();
                    }
                    break;

                case PROCESSING:
                    // 正在处理中，忽略所有音频帧
                    break;
            }
        } catch (Exception e) {
            logger.error("【引擎】处理音频帧时出错", e);
        }
    }

    /**
     * 步骤 1：处理完整的指令音频流
     */
    private void handleCommand(byte[] commandAudio) {
        String action = null;
        try {
            // 步骤 1.1: STT
            String userQuery = performSTT(commandAudio);
            if (userQuery == null) {
                return; // STT 失败或为空，performSTT 内部已处理状态
            }

            // 步骤 1.2: 处理元指令 (退出, 休眠, 清除记忆)
            boolean metaHandled = handleMetaCommands(userQuery);
            if (metaHandled) {
                return; // 元指令已处理，状态已设置
            }

            // 步骤 1.3: 正常 NLU -> Dispatch 流程
            action = dispatchNLUCommand(userQuery);

        } catch (Exception e) {
            logger.error("【引擎】处理指令时发生未知错误", e);
            ttsModule.speak("抱歉，执行指令时出错了。");
        } finally {
            // 步骤 1.4: 状态机管理
            // 只有在不是“问答”指令时，才在这里重置状态。
            // “问答”指令 (answer_question) 是异步流式，由 NLUModule 自己重置状态。
            if (currentState == State.PROCESSING && !"answer_question".equals(action)) {
                logger.info("【状态机】(同步)指令处理完毕，返回 SLEEPING 状态。");
                setAssistantState(State.SLEEPING);
            } else if ("answer_question".equals(action)) {
                logger.info("【状态机】(异步)问答指令已分派，等待流式线程重置状态...");
            } else if (currentState == State.PROCESSING) {
                // 兜底：如果 action 为空（例如 NLU 失败）或 command 为 null
                logger.info("【状态机】(兜底)处理出错或 action 为空，返回 SLEEPING 状态。");
                setAssistantState(State.SLEEPING);
            }
        }
    }

    /**
     * 步骤 1.1：执行 STT
     * @return 识别的文本，如果失败则返回 null
     */
    private String performSTT(byte[] commandAudio) {
        if (commandAudio.length == 0) {
            logger.warn("【STT】VAD 缓冲区为空，可能误触发。");
            setAssistantState(State.SLEEPING);
            return null;
        }

        logger.info("【流程】开始执行 STT ({} 字节)...", commandAudio.length);
        String userQuery = sttModule.recognizeSpeech(commandAudio);

        if (userQuery == null || userQuery.trim().isEmpty()) {
            logger.warn("【STT结果】STT 未能识别出任何文本。");
            ttsModule.speak("没听清呢，要不你再说一遍？");
            setAssistantState(State.SLEEPING);
            return null;
        }

        logger.info("【STT结果】: {}", userQuery);
        return userQuery;
    }

    /**
     * 步骤 1.2：处理元指令
     * @return true 如果元指令被处理，否则 false
     */
    private boolean handleMetaCommands(String userQuery) {
        if (userQuery.contains("退出") || userQuery.contains("再见") || userQuery.contains("结束") || userQuery.contains("关机") || userQuery.contains("拜拜")) {
            logger.info("检测到'退出'指令，关闭程序。");
            ttsModule.speak("我们下次再见啦");
            // 注意：这里直接退出，状态机无需管理
            System.exit(0); 
            return true;
        }

        if (userQuery.contains("清除记忆") || userQuery.contains("忘记刚才说的")) {
            logger.info("检测到清除历史指令。");
            nluModule.clearHistory();
            ttsModule.speak("OK，我全忘了。");
            setAssistantState(State.SLEEPING);
            return true;
        }
        return false;
    }

    /**
     * 步骤 1.3：NLU -> Dispatch -> TTS 流程
     * @return 返回 NLU 解析出的 action 字符串
     */
    private String dispatchNLUCommand(String userQuery) {
        // 1. 意图识别 (NLU)
        logger.info("【流程】开始执行 NLU，指令：{}", userQuery);
        CommandData command = nluModule.parseCommand(userQuery);
        String action = command.getAction();
        String feedbackText;

        // 2. 【重构】错误处理移至引擎层
        if (action.isEmpty()) {
            feedbackText = "对不起，我未能识别您的指令意图，请再说一遍。";
        } else if (action.equals("error_ratelimit")) {
            logger.warn("【API限制】已达到 API 速率限制。");
            feedbackText = "抱歉，API 请求过于频繁，请稍后再试。";
        } else if (action.equals("error")) {
            logger.warn("【NLU错误】NLU 模块返回错误：{}", command.getPrompt());
            feedbackText = command.getPrompt(); // prompt 字段包含错误信息
        } else {
            // 3. 指令调度与执行 (Dispatcher)
            logger.info("【流程】开始执行指令调度...");
            feedbackText = dispatcher.dispatch(command);
        }

        // 4. 语音反馈 (TTS)
        logger.info("【TTS反馈】: {}", feedbackText);
        ttsModule.speak(feedbackText);

        return action; // 返回 action 供 handleCommand 的 finally 块使用
    }

    /**
     * 全局静态状态机设置方法
     */
    public synchronized void setAssistantState(State newState) {
        if (currentState != newState) {
            logger.info("【状态机】状态变更: {} -> {}", currentState, newState);
            currentState = newState;
        }
    }
}